#include "proc.h"
#include "memo.h"
#include "string.h"
#include "print.h"

//#define NPROC 2

struct proc allProc[NPROC];
struct proc *curproc;
struct proc *initproc;
// Arrange that cp point to the struct proc  
struct proc *cp;  //  Current process on CPU

struct proc *allocProc ()
{
  int i;
  struct proc *p;

  for(i = 0; i < NPROC; i++)
    {
      p = &(allProc[i]);
      if(p->state == UNUSED)
	{
	  p->state = RUNNABLE;          
	  return p;
	}
    }
  myPrintf ("error: initial process table is full\n");
  return 0;
}


// Grow current process's memory by n bytes.
// Return old size on success, -1 on failure.
/* int growproc(int n) */
/* { */
/*   char *newmem; */
/*   char *oldmem; */

/*   newmem = kalloc(cp->sz + n); */
/*   if(newmem == 0) */
/*     return -1; */
/*   memmove(newmem, cp->mem, cp->sz); */
/*   memset(newmem + cp->sz, 0, n); */
/*   oldmem = cp->mem; */
/*   cp->mem = newmem; */
/*   kfree(oldmem, cp->sz); */
/*   cp->sz += n; */
/*   return cp->sz - n; */
/* } */


// Set up first user process.
void userInit ()
{
  struct proc *p;
  extern uchar _binary_initCode_start[], _binary_initCode_size[];
  
  if((p =allocProc()) == 0)
    {
      myPrintf ("error: allocate the first process failed\n");
      return;
    }

  if((p->kstack = kalloc(KSTACKSIZE)) == 0)
    {
      myPrintf ("error: allocate process kernel stack failed\n");
      p->state = UNUSED;
      return;
    }
  
  p->sz = PAGE;
  p->mem = kalloc (p->sz);
  myPrintf ("the first allocation address=%d\n", p->mem);

  (p->mc).eip = 0;
  (p->mc).ebp = PAGE;
  (p->mc).esp = PAGE;
  (p->mc).mem = 0;
  myPrintf ("about to copy code to---> %d\n", p->mem);

  memmove (0, _binary_initCode_start, (int)_binary_initCode_size);
  safeStrcpy (p->name, "initcode", sizeof(p->name));
  p->state = RUNNABLE;
  
  initproc = p;
}

void procScheduler ()
{
  int i = 0;
  
  myPrintf ("about to context switching:\n");
  contextSwitch (0, &(initproc->mc));
  return;
}

void procExit()
{
  if(cp == initproc)
    panic ("init exiting");
  
  kfree (cp->mem, cp->sz);
  kfree (cp->kstack, KSTACKSIZE);
  cp->state = UNUSED;
  cp->name[0]=0;
  return;
}

